/**
 * Copyright 厦门中软海晟信息技术有限公司 版权所有 违者必究 2019
 */
package com.opencvjava.piano;

import org.opencv.core.Mat;
import org.opencv.core.Point;
import org.opencv.core.Rect;
import org.opencv.core.Scalar;
import org.opencv.core.Size;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

import static com.opencvjava.support.util.CvUtils.imshow;
import static com.opencvjava.support.util.CvUtils.mat;
import static org.opencv.imgcodecs.Imgcodecs.imwrite;

/**
 * @author : sunzb
 * @date: 2019/11/27
 */
@Service
public class Extract4 {

    private byte[] data;
    private Mat gray, src;
    private int rows, cols, total, lineLength, rowIndex, whiteLineThreshold;
    private String testPath = "F:\\project\\cv\\opencv-java\\src\\main\\resources\\test\\";

    public void test() {
        src = mat("piano", "4.jpg");
        gray = mat("piano", "gray4.jpg", Imgcodecs.IMREAD_GRAYSCALE);
        if (gray.empty()) throw new RuntimeException("源图读取失败");
        rows = gray.rows();
        cols = gray.cols();
        total = (int) gray.total();
        lineLength = cols / 3 * 2;
        if (cols < 500) whiteLineThreshold = 10;
        else whiteLineThreshold = 10;
        data = new byte[total];
        gray.get(0, 0, data);
        // 取4角判断是否为电子版
        boolean isDigit = isDigit(data);
        System.out.println("电子版:" + isDigit);
//        if (isDigit) digitProcess3();
        if (isDigit) digitProcess4();
    }

    private void digitProcess4() {
        for (int i = 0; i < total; i++) if ((data[i] & 0xff) > 199) data[i] = -1;
        gray.put(0, 0, data);
        imwrite(testPath + "graybin.jpg", gray);
        imshow("graybin", gray);
        List<Integer> lineRowIndex = new ArrayList<>();
        int rowIndex;
        outer:
        for (int row = 0; row < rows; row++) {
            rowIndex = row * cols;
            int count = 0;
            for (int col = 0; col < cols; col++) {
                if (data[rowIndex + col] != -1) {
                    count++;
                }
            }

            if (count < whiteLineThreshold) {
                lineRowIndex.add(row);
            }
        }
        for (int row : lineRowIndex) {
            Imgproc.line(src, new Point(0, row), new Point(cols - 1, row), new Scalar(0, 0, 255), 1);
        }
        imshow("dst", src);
    }

    private void digitProcess3() {
        for (int i = 0; i < total; i++) if ((data[i] & 0xff) > 199) data[i] = -1;
        gray.put(0, 0, data);
        imwrite(testPath + "graybin.jpg", gray);
        imshow("graybin", gray);
        int count = 0;
        List<Block> blockList = new ArrayList<>();
        for (int row = 3; row < rows - 5; row++) {
            colIte:
            for (int col = 3; col < cols / 2; col++) {
                int leftCount = 0;
                int rightCount = 0;
                for (int row1 = row - 3; row1 < row + 4; row1++)
                    for (int col1 = col - 3; col1 <= col; col1++) if (data[row1 * cols + col1] == -1) leftCount++;
                for (int row1 = row - 3; row1 < row + 4; row1++)
                    for (int col1 = col; col1 < col + 4; col1++) if (data[row1 * cols + col1] != -1) rightCount++;
                if (leftCount > 22 && rightCount > 6) {
                    int rowEnd = row + 4;
                    for (int col2 = col; col2 < cols; col2++) {
                        boolean find = false;
                        for (int row2 = row - 3; row2 < row + 4; row2++) {
                            if (data[row2 * cols + col] == -1) continue;
                            else {
                                find = true;
                                /*int row3 = row2;
                                while (true) {
                                    if (data[(++row3) * cols + col2] == -1) break;
                                    else {
                                        if (rowEnd < row3) rowEnd = row3;
                                    }
                                    if (row3 == rows) rowEnd = rows;
                                }*/
                            }
                        }
                        if (!find) {
                            blockList.add(new Block().setColStart(col).setRowStart(row - 3)
                                    .setColEnd(col2).setRowEnd(rowEnd));
                            row = rowEnd + 6;
                            break colIte;
                        }
                    }
                }
            }
        }
        System.out.println("块:" + blockList.size());
        gray.put(0, 0, data);
        imwrite(testPath + "grayCorner.jpg", gray);
        imshow("grayCorner", gray);
        for (Block block : blockList) {
            int x = block.getColStart(), y = block.getRowStart();
            int width = block.getColEnd() - block.getColStart(), height = block.getRowEnd() - block.getRowStart();
            System.out.println(String.format("x=%s, y=%s, width=%s, height=%s", x, y, width, height));
            Imgproc.rectangle(src, new Rect(x, y, 20, height), new Scalar(0, 0, 255), 1, 8, 0);
//            Imgproc.rectangle(src, new Rect(29, 41, 20, 20), new Scalar(0, 0, 255), 1, 8, 0);
        }
        imshow("dst", src);
    }

    private void digitProcess2() {
        for (int i = 0; i < total; i++) if ((data[i] & 0xff) > 199) data[i] = -1;
        gray.put(0, 0, data);
        imwrite(testPath + "graybin.jpg", gray);
        imshow("graybin", gray);
        int colsEnd = cols / 4 * 3;
        int count = 0;
        for (int col = cols - 4; col > colsEnd; col--) {
            for (int row = 3; row < rows - 3; row++) {
                int rowIndex = row * cols;
                int index = rowIndex + col;
                int index1 = rowIndex + col - 1;
                int index2 = rowIndex + col - 2;
                int index3 = rowIndex + col - 3;
                int index4 = (row + 1) * cols + col;
                int index5 = (row + 2) * cols + col;
                int index6 = (row + 3) * cols + col;
                int index7 = (row + 2) * cols + col - 2;
                int index8 = (row + 2) * cols + col - 3;
                int index9 = (row + 3) * cols + col - 2;
                int index10 = (row + 3) * cols + col - 3;
                if (data[index] != -1 && data[index1] != -1 && data[index2] != -1 &&
                        data[index3] != -1 && data[index4] != -1 && data[index5] != -1 &&
                        data[index6] != -1 && data[index7] == -1 && data[index8] == -1 &&
                        data[index9] == -1 && data[index10] == -1) {
                    for (int col1 = cols - 4; col1 > colsEnd; col1--) {
                        for (int row1 = row - 3; row1 < row + 4; row1++) {
                            data[row1 * cols + col1] = -1;
                        }
                    }
                    count++;
                    row += 4;
                }
            }
        }
        System.out.println("角点数量:" + count);
        gray.put(0, 0, data);
        imwrite(testPath + "grayCorner.jpg", gray);
        imshow("grayCorner", gray);
    }

    private void digitProcess() {
        for (int i = 0; i < total; i++) if ((data[i] & 0xff) > 199) data[i] = -1;
        gray.put(0, 0, data);
        imwrite(testPath + "grayBin.jpg", gray);
        imshow("grayBin", gray);
        int count, rowIndex;
        for (int row = 0; row < rows; row += 3) {
            rowIndex = row * cols;
            count = 0;
            for (int col = 0; col < cols; col++) {
                if (data[rowIndex + col] != -1 ||
                        data[rowIndex + col + cols] != -1 ||
                        data[rowIndex + col + cols * 2] != -1) count++;
            }
            if (count > cols / 3 * 2) {
                System.out.println("row:" + row);
                for (int col = 0; col < cols; col++) {
                    data[rowIndex + col] = 0;
                }
            }
        }
        gray.put(0, 0, data);
        imwrite("I:\\project\\cv\\opencv-java\\src\\main\\resources\\test\\grayLine.jpg", gray);
        imshow("grayLine", gray);
    }

    private boolean isDigit(byte[] data) {
        int count = 0, color;
        // 左上
        for (int row = 0; row < 10; row++) {
            rowIndex = row * cols;
            for (int col = 0; col < 10; col++) {
                if ((data[rowIndex + col] & 0xff) > 245) count++;
            }
        }
        // 左下
        for (int row = rows - 10; row < rows; row++) {
            rowIndex = row * cols;
            for (int col = 0; col < 10; col++) {
                if ((data[rowIndex + col] & 0xff) > 245) count++;
            }
        }
        // 右上
        for (int row = 0; row < 10; row++) {
            rowIndex = row * cols;
            for (int col = cols - 10; col < cols; col++) {
                if ((data[rowIndex + col] & 0xff) > 245) count++;
            }
        }
        // 右下
        for (int row = rows - 10; row < rows; row++) {
            rowIndex = row * cols;
            for (int col = cols - 10; col < cols; col++) {
                if ((data[rowIndex + col] & 0xff) > 245) count++;
            }
        }
        return count > 300;
    }

    private class Block {
        private int rowStart;
        private int rowEnd;
        private int colStart;
        private int colEnd;

        public int getRowStart() {
            return rowStart;
        }

        public Block setRowStart(int rowStart) {
            this.rowStart = rowStart;
            return this;
        }

        public int getRowEnd() {
            return rowEnd;
        }

        public Block setRowEnd(int rowEnd) {
            this.rowEnd = rowEnd;
            return this;
        }

        public int getColStart() {
            return colStart;
        }

        public Block setColStart(int colStart) {
            this.colStart = colStart;
            return this;
        }

        public int getColEnd() {
            return colEnd;
        }

        public Block setColEnd(int colEnd) {
            this.colEnd = colEnd;
            return this;
        }
    }
}
